package com.lovi.notepaper.adapters;

import android.annotation.SuppressLint;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.lovi.notepaper.R;
import com.lovi.notepaper.entities.Note;
import com.lovi.notepaper.listeners.NotesListeners;
import com.makeramen.roundedimageview.RoundedImageView;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * NotesAdapter 类，用于展示笔记列表
 * 并且实现了搜索功能
 * ViewHolder(作用是将视图绑定到数据)
 *
 * 下面几个继承RecyclerView的方法在 RecyclerView 的生命周期中会被自动调用。
 */
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.NoteViewHolder> {
    List<Note> notes;  // 笔记数据列表
    private NotesListeners notesListeners;  // 笔记列表的点击事件监听器
    private Timer timer;  // 定时器
    private List<Note> noteSource;  // 笔记数据源


    /**
     * 构造函数，用于初始化数据
     *
     * @param notes     笔记数据列表
     * @param listeners 笔记列表的点击事件监听器
     */
    public NotesAdapter(List<Note> notes, NotesListeners listeners) {
        this.notesListeners = listeners;
        this.notes = notes;
        this.noteSource = notes;
        //noteSource 是一个备份，它的值也是 notes。这样做是为了在搜索过程中，能够将 noteSource 恢复为最初的笔记数据源，以便下一次搜索时能够正确地进行搜索。
    }

    /**
     * 创建 ViewHolder
     *
     * @param parent   父容器
     * @param viewType 视图类型
     * @return ViewHolder
     */
    @NonNull
    @Override
    public NoteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new NoteViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_container_note, parent, false));
    }

    /**
     * 绑定 ViewHolder
     *
     * @param holder   ViewHolder
     * @param position 位置
     */
    @Override
    public void onBindViewHolder(@NonNull NoteViewHolder holder, int position) {//position指笔记在列表中的位置,并不是笔记的id
        holder.setNote(notes.get(position));  // 设置笔记数据
        holder.layoutNote.setOnClickListener(v -> {
            notesListeners.onNoteClicked(notes.get(position), position);  // 处理笔记点击事件
        });
    }

    /**
     * 获取列表项数量
     *
     * @return 列表项数量
     */
    @Override
    public int getItemCount() {
        return notes.size();
    }

    /**
     * 获取列表项视图类型
     *
     * @param position 位置
     * @return 视图类型
     */
    @Override
    public int getItemViewType(int position) {
        return position;
    }


    /**
     * NoteViewHolder 类，用于展示笔记列表项
     */
    static class NoteViewHolder extends RecyclerView.ViewHolder {
        TextView textTitle, textSubtitle, textDateTime;
        LinearLayout layoutNote;
        RoundedImageView imageNote;
        //初始化
        public NoteViewHolder(@NonNull View itemView) {
            super(itemView);
            textTitle = itemView.findViewById(R.id.textTitle);
            textSubtitle = itemView.findViewById(R.id.textSubtitle);
            textDateTime = itemView.findViewById(R.id.textDateTime);
            layoutNote = itemView.findViewById(R.id.layoutNote);
            imageNote = itemView.findViewById(R.id.imageNote);
        }

        /**
         * 设置笔记数据(标题，子标题，图片）
         *
         * @param note 笔记数据
         */
        void setNote(Note note) {
            textTitle.setText(note.getTitle());
            //副标题有就展示，没有就回收
            if (note.getSubtitle().trim().isEmpty()) {
                textSubtitle.setVisibility(View.GONE);//View.GONE 是一个常量值，表示该视图不仅不可见，而且也不占用任何空间。这意味着，当一个控件被设置为 View.GONE 时，它与其他控件之间的间隙也会消失，从而达到完全不显示的效果。
            } else {
                textSubtitle.setText(note.getSubtitle());
            }
            textDateTime.setText(note.getDateTime());


            // 设置背景色
            //GradientDrawable 是 Drawable 类的一个子类，其中包含了渐变、形状、边框、圆角等属性设置。
            GradientDrawable gradientDrawable = (GradientDrawable) layoutNote.getBackground();
            if (note.getColor() != null) {
                gradientDrawable.setColor(Color.parseColor(note.getColor()));
            } else {
                gradientDrawable.setColor(Color.parseColor("#333333"));
            }

            if (note.getImagePath() != null) {
                //BitmapFactory.decodeFile() 方法将该路径对应的图片文件解码为一个 Bitmap 对象，并将该对象设置为笔记条目的图片。
                imageNote.setImageBitmap(BitmapFactory.decodeFile(note.getImagePath()));
                imageNote.setVisibility(View.VISIBLE);
            } else {
                imageNote.setVisibility(View.GONE);//View.GONE 是一个常量值，表示该视图不仅不可见，而且也不占用任何空间。这意味着，当一个控件被设置为 View.GONE 时，它与其他控件之间的间隙也会消失，从而达到完全不显示的
            }
        }
    }

    /**
     * 搜索笔记
     *
     * @param searchKeyWord 搜索关键字
     */
    public void searchNotes(final String searchKeyWord){
        //设置定时器: 需要在用户输入搜索关键字后等待一段时间再进行搜索操作，以避免用户频繁输入导致搜索操作过于频繁，影响应用的性能和用户体验。
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                Log.d("Timer","定时任务执行中");
                if(searchKeyWord.trim().isEmpty()){
                    notes = noteSource;
                }else{
                    ArrayList<Note> temp = new ArrayList<>();
                    for(Note note : noteSource){
                        if(note.getTitle().toLowerCase().contains(searchKeyWord.toLowerCase())
                                || note.getSubtitle().toLowerCase().contains(searchKeyWord.toLowerCase())
                                || note.getNoteText().toLowerCase().contains(searchKeyWord.toLowerCase()) ){
                            //把符合搜索条件的笔记放到temp当中
                            temp.add(note);
                        }
                    }
                    notes = temp;
                }
                /*
                这段代码的作用是在主线程中更新笔记列表。具体来说，它创建了一个新的 `Handler` 对象，并将其绑定到主线程的 `Looper` 上，
                然后通过 `post()` 方法在主线程中执行一个 `Runnable` 对象。在 `Runnable` 对象的 `run()` 方法中，
                调用 `notifyDataSetChanged()` 方法，通知适配器数据已经发生了变化，需要更新笔记列表。

                在 Android 应用中，UI 更新必须在主线程中进行，否则可能会导致应用崩溃或出现其他异常。
                由于 `notifyDataSetChanged()` 方法必须在主线程中调用，因此我们需要使用 `Handler` 将其提交到主线程中执行。

                在 `NotesAdapter` 中，这个方法通常在数据源发生变化时调用，用于更新笔记列表。例如，当用户添加、删除或编辑笔记时，
                就需要调用该方法来更新笔记列表。通过在主线程中更新笔记列表，可以确保应用的稳定性和流畅性。
                 */
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @SuppressLint("NotifyDataSetChanged")
                    @Override
                    public void run() {
                        notifyDataSetChanged();
                    }
                });
            }
        },500);
    }

    /**
     * 取消定时器
     */
    public void cancelTimer(){
        if(timer != null){
            timer.cancel();
        }
    }
}
